﻿using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteStep.Exchanges.MtGox;
using Newtonsoft.Json;
using LiteStep.Currencies;
using EventBus;
using LiteStep.Events;
using System.Diagnostics;

namespace LiteStep.DataSources.MtGox
{
	public class MtGoxRestApi2 : IDataSource
	{
		private RestClient restClient { get; set; }
		private IEventBus eventBus { get; set; }

		private bool running { get; set; }

		public MtGoxRestApi2(RestClient restClient, IEventBus eventBus)
		{
			LiteStep.Log.Debug("Creating MtGoxRestApi2");

			this.restClient = restClient;
			this.eventBus = eventBus;
			this.running = false;
		}

		~MtGoxRestApi2()
        {
			LiteStep.Log.Debug("Destroying MtGoxRestApi2");

            Stop();
        }

		public void Start(int seconds)
		{
			LiteStep.Log.Info("Starting MtGoxRestApi2");

			running = true;
			ContinuouslyPollTicker<Btc, Usd>(seconds);
			ContinuouslyPollTicker<Btc, Eur>(seconds);
			ContinuouslyPollTicker<Btc, Jpy>(seconds);
			ContinuouslyPollTicker<Btc, Cad>(seconds);
			ContinuouslyPollTicker<Btc, Gbp>(seconds);
			ContinuouslyPollTicker<Btc, Chf>(seconds);
			ContinuouslyPollTicker<Btc, Rub>(seconds);
			ContinuouslyPollTicker<Btc, Aud>(seconds);
			ContinuouslyPollTicker<Btc, Sek>(seconds);
			ContinuouslyPollTicker<Btc, Dkk>(seconds);
			ContinuouslyPollTicker<Btc, Hkd>(seconds);
			ContinuouslyPollTicker<Btc, Pln>(seconds);
			ContinuouslyPollTicker<Btc, Cny>(seconds);
			ContinuouslyPollTicker<Btc, Sgd>(seconds);
			ContinuouslyPollTicker<Btc, Thb>(seconds);
			ContinuouslyPollTicker<Btc, Nzd>(seconds);
			ContinuouslyPollTicker<Btc, Nok>(seconds);
		}

		public void Stop()
		{
			LiteStep.Log.Info("Stopping MtGoxRestApi2");

			running = false;
		}

		public async Task<Ticker<TFrom, TTo>> GetTickerAsync<TFrom, TTo>()
			where TFrom : ICurrency
			where TTo : ICurrency
		{
			TickerResponse<TFrom, TTo> tickerResponse = null;

			try
			{
				eventBus.FireEvent(new BeforeTickerRequestEvent<Ticker<TFrom, TTo>>());
				tickerResponse = await restClient.GetResponseAsync<TickerResponse<TFrom, TTo>>(
					new RestRequest(String.Format("{0}{1}/money/ticker", typeof(TFrom).Name.ToUpper(), typeof(TTo).Name.ToUpper()), Method.GET));
			}
			finally
			{
				Ticker<TFrom, TTo> ticker = tickerResponse != null && tickerResponse.Status == ResponseStatus.Success ? 
					tickerResponse.Ticker : null;
				eventBus.FireEvent(new AfterTickerResponseEvent<Ticker<TFrom, TTo>>(ticker));
			}
			
			return tickerResponse != null && tickerResponse.Status == ResponseStatus.Success ? tickerResponse.Ticker : null;
		}

		public async void ContinuouslyPollTicker<TFrom, TTo>(int seconds)
			where TFrom : ICurrency
			where TTo : ICurrency
		{
			while (running)
			{
				var ticker = await GetTickerAsync<TFrom, TTo>();
				await Task.Delay(seconds * 1000);
			}
		}

		public class RestClient : RestSharp.RestClient
		{
			public RestClient(string baseUrl)
				: base(baseUrl)
			{
			}

			public T GetResponse<T>(RestRequest request)
			{
				var response = Execute(request);
				if (response.Content.Contains("error"))
					throw new Exception("Response contained error: " + response.Content);
				return JsonConvert.DeserializeObject<T>(response.Content);
			}

			public Task<T> GetResponseAsync<T>(RestRequest request)
			{
				return Task.Factory.StartNew(() => GetResponse<T>(request));
			}
		}

		private class TickerResponse<TFrom, TTo>
			where TFrom : ICurrency
			where TTo : ICurrency
		{ 
			[JsonProperty(PropertyName = "result")]
			public ResponseStatus Status { get; set; }
			[JsonProperty(PropertyName = "data")]
			public Ticker<TFrom, TTo> Ticker { get; set; }
		}
	}
}
